package common.utils;

import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * Created by jihb on 8/3/16.
 */
public class ZipUtils {
    private static Logger logger = LoggerFactory.getLogger(ZipUtils.class);
    public static boolean unzipFile(String filePath, String destPath){
        File file = new File(filePath);
        if (!file.exists()){
            logger.debug("zip文件不存在");
            return false;
        }
        if (!destPath.endsWith("/")){
            destPath += "/";
        }
        try {
            FileUtils.forceMkdir(new File(destPath));
            ZipFile zipFile = new ZipFile(file);
            Enumeration zipArchiveEntrys = zipFile.getEntries();
            List<String> subDir = new ArrayList<>();
            while (zipArchiveEntrys.hasMoreElements()){
                ZipArchiveEntry zipArchiveEntry = (ZipArchiveEntry) zipArchiveEntrys.nextElement();
                if (zipArchiveEntry.isDirectory()){
                    FileUtils.forceMkdir(new File(String.format("%s%s",destPath, File.separator)));
                    subDir.add(String.format("%s%s",destPath,zipArchiveEntry.getName(), File.separator));
                }else{
                    IOUtils.copy(zipFile.getInputStream(zipArchiveEntry), FileUtils.openOutputStream(new File(String.format("%s%s",destPath,zipArchiveEntry.getName()))));
                }
            }
            if (subDir.size() > 0){
                for (String subDirPath:subDir){
                    copySubFile(subDirPath,destPath);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        logger.debug("解压成功");
        return true;
    }

    public static void copySubFile(String subDirPath, String destPath){
        if (!destPath.endsWith("/")){
            destPath += "/";
        }
        File destFile = new File(destPath);
        try {
            File file = new File(subDirPath);
            if (file.isFile()){
                IOUtils.copy(new FileInputStream(file),new FileOutputStream(destFile));
            }else if (file.isDirectory()){
                File[] subFiles = file.listFiles();
                if (subFiles != null && subFiles.length > 0){
                    for (File subFile:subFiles){
                        if (subFile.isDirectory()){
                            copySubFile(String.format("%s%s",subDirPath,subFile.getName()),destPath);
                        }else if (subFile.isFile()){
                            IOUtils.copy(new FileInputStream(subFile),new FileOutputStream(String.format("%s%s",destPath,subFile.getName())));
                        }
                    }
                }
                FileUtils.deleteDirectory(file);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean zipFile(String srcPath, String destPath){
        File srcFile = new File(srcPath);
        if (!srcFile.exists()){
            return false;
        }
        String fileName = srcFile.getName();
        if (!destPath.endsWith(".zip")){
            if (!destPath.endsWith("/")){
                destPath += "/";
            }
            destPath = destPath+fileName.substring(0,fileName.lastIndexOf("."))+".zip";
        }

        File zipFile = new File(destPath);
        ZipArchiveOutputStream zaos = null;
        try {
            FileUtils.forceMkdir(zipFile);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(zipFile));
            zaos = new ZipArchiveOutputStream(bos);
            zaos.setUseZip64(Zip64Mode.AsNeeded);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        }catch (IOException e) {
            e.printStackTrace();
        }
        return unpackFiles(zaos,srcPath,destPath);
    }

    private static boolean unpackFiles(ZipArchiveOutputStream zaos, String srcPath, String destPath){
        File srcFile = new File(srcPath);
        if (!srcFile.exists()){
            return false;
        }
        if (srcFile.isDirectory()) {
            File[] files = srcFile.listFiles();
            if (files == null || files.length < 1) {
                return false;
            }
            for (File file:files){
                if (file.exists() && file.isDirectory()){
                    return unpackFiles(zaos,file.getAbsolutePath(),destPath+file.getName()+ File.separator);
                }else{
                    return copyFile(file,zaos);
                }
            }
        }
       return copyFile(srcFile,zaos);
    }

    private static boolean copyFile(File file, ZipArchiveOutputStream zaos){
        try {
            zaos.putArchiveEntry(new ZipArchiveEntry(file,file.getName()));
            IOUtils.copy(new FileInputStream(file.getAbsoluteFile()),zaos);
            zaos.closeArchiveEntry();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     *
     * @Description (解压)
     * @param zipPath zip路径
     * @param charset 编码
     * @param outPutPath 输出路径
     */
    public static void decompression(String zipPath, String charset, String outPutPath) {
        long startTime= System.currentTimeMillis();
        try {
            ZipInputStream Zin=new ZipInputStream(new FileInputStream(zipPath), Charset.forName(charset));//输入源zip路径
            BufferedInputStream Bin=new BufferedInputStream(Zin);
            String Parent = outPutPath; //输出路径（文件夹目录）
            File Fout=null;
            ZipEntry entry;
            try {
                while((entry = Zin.getNextEntry())!=null && !entry.isDirectory()){
                    Fout=new File(Parent,entry.getName());
                    if(!Fout.exists()){
                        (new File(Fout.getParent())).mkdirs();
                    }
                    FileOutputStream out=new FileOutputStream(Fout);
                    BufferedOutputStream Bout=new BufferedOutputStream(out);
                    int b;
                    while((b=Bin.read())!=-1){
                        Bout.write(b);
                    }
                    Bout.close();
                    out.close();
                    System.out.println(Fout+"解压成功");
                }
                Bin.close();
                Zin.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        long endTime= System.currentTimeMillis();
        System.out.println("耗费时间： "+(endTime-startTime)+" ms");
    }
}
